
package com.kweative.model.data;

import com.kweative.model.Index;
import com.kweative.model.Table;
import com.kweative.model.exception.StructureException;
import com.kweative.model.column.Column;
import com.kweative.model.column.ColumnComplex;
import com.kweative.model.column.ColumnExtra;
import com.kweative.model.column.IColumn;
import com.kweative.model.relation.Relation;
import com.kweative.model.relation.RelationOne2One;
import com.mysql.jdbc.Driver;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 *
 * @author henrik
 */
public class MySQL extends DataProvider {
    

    public MySQL(String username, String password) throws SQLException {
        this(username, password,"localhost");
    }
    public MySQL(String username, String password, String host) throws SQLException {
        this(username, password,host, 3306);
    }
    public MySQL(String username, String password, String host, int port) throws SQLException {
        super(new Driver(),username, password,host, port);
        properties.setProperty("user",getUsername());
        properties.setProperty("password",getPassword());
    }


	@Override
	public String serializeTable(Table tbl) throws StructureException {
		StringBuilder sb = new StringBuilder();
		sb.append(String.format("CREATE TABLE IF NOT EXISTS `%s`.`%s` (\n", tbl.getSchema().getName(),tbl.getName()));
		boolean first = true;
        boolean definedPrimary = false;
		for(Iterator<IColumn> it = tbl.getColumns().values().iterator();it.hasNext();) {
			IColumn f = it.next();

            if (f instanceof ColumnComplex) {
                ColumnComplex fc = (ColumnComplex) f;
                LinkedList<Column> cols = fc.getColumns();
                for(Column cs : cols) {
                    if (!first)
                        sb.append(",\n");
                    sb.append(serializeColumn(cs));
                    first = false;
                }
                continue;
            }


            Column fs = (Column) f;
            if (fs.hasSQLExtra(ColumnExtra.AUTO_INCREMENT)) {
                definedPrimary = true;
            }
            if (!first)
                sb.append(",\n");
            sb.append(serializeColumn(fs));
            first = false;

		}
        TableEngines tblEngine = (TableEngines) tbl.getParam(TableEngines.class, TableEngines.INNODB);
        ArrayList<Index> indexes = tbl.getIndexes();
        for(Index ix:indexes) {
            if (ix.getType().equals(Index.Type.PRIMARY) && definedPrimary) continue;
            sb.append(",\n");
            String name = "";
            String type = "";
            
            switch(ix.getType()) {
                default:
                case INDEX:
                    type = "KEY";
                    name = ix.getName();
                    break;
                case UNIQUE:
                    type = "UNIQUE KEY";
                    name = ix.getName();
                    break;
                case PRIMARY:
                    type = "PRIMARY KEY";
                    break;
                case TEXT:
                    if (!tblEngine.equals(TableEngines.MYISAM))
                        throw new StructureException("Only MYISAM engine supports full text indexes in MySQL");
                    type = "FULLTEXT KEY";
                    name = ix.getName();
                    break;

            }
            if (name.length() > 0)
                name = String.format("`%s` ",name);
            sb.append(String.format("%s %s(%s)",type,name,makeColumnList(ix.getColumns())));

        }
		
        //Relations
        if (tbl.getRelations().size() > 0) {
            LinkedList<Relation> relations = tbl.getRelations();
            int i = 0;
            for(Relation rel:relations) {
                if (rel instanceof RelationOne2One) {
                    String name = String.format("%s_fk_%s",tbl.getName(),i);
                    sb.append(",\n");
                    
                    i++;
                    RelationOne2One o2o = (RelationOne2One) rel;
                    sb.append(String.format("FOREIGN KEY `%s` (`%s`) REFERENCES `%s` (`%s`) ON DELETE CASCADE ON UPDATE CASCADE",
                            name,
                            o2o.getChildColumn().getName(),
                            o2o.getParent().getName(),
                            o2o.getParentColumn().getName()));
                }
            }
        }
        sb.append("\n) ENGINE=")
			.append(tblEngine.toString())
            .append(" DEFAULT CHARSET=utf8;\n");

		return sb.toString();
	}
    @Override
    public String serializeColumn(Column f) {
        StringBuilder sb = new StringBuilder();
		sb.append(super.serializeColumn(f));
        if (f.hasSQLExtra(ColumnExtra.AUTO_INCREMENT))
            sb.append(" PRIMARY KEY");
        return sb.toString();
    }
    private String makeColumnList(List<IColumn> cols) {
        StringBuilder sb = new StringBuilder();
        boolean first = true;
		for(Iterator<IColumn> it = cols.iterator();it.hasNext();) {
			IColumn f = it.next();
			for(String name: f.getColumnNames()) {
				if (!first)
					sb.append(",");
				sb.append(String.format("`%s`",name));
			}
			first = false;
		}
        return sb.toString();
    }

    @Override
    public String getConnectionString() {
        return String.format("jdbc:mysql://%s:%s/",getHost(),getPort());
    }

	public enum TableEngines {
		INNODB,
		MYISAM,
        MEMORY
	}

}
